import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;


/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: lishuo
 * Date: 2023-05-17
 * Time: 21:32
 */
// Echo-回显客户端服务器。客户端发了个请求，服务器返回一个一模一样的响应。

public class UdpEchoSever {
    // 需要先定义一个 socket 对象，使用网络通信，必须要使用 socekt 对象
    private DatagramSocket socket = null;
    // 绑定一个端口号，不一定能成功，比如某个端口号已经被别的进程占用了，此时这里的绑定操作就会出错。
    // 需要注意的是：同一个主机上，一个端口，同一时刻，只能被一个进程绑定。
    public UdpEchoSever(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }

    // 启动服务器主逻辑
    public void start() throws IOException {
        System.out.println("服务器启动！");
        while (true) {
            // 每次循环，做三件事
            // 1. 读取请求并解析
            //    类比于食堂阿姨帮忙打饭，构造一个空饭盒
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            //    食堂大妈给饭盒里盛饭（从网卡上接收请求）此处的 requestPacket 为输出型参数
            socket.receive(requestPacket);
            //    这里为了方便处理这个请求，将数据包转化为 String
            String request = new String(requestPacket.getData(),0,requestPacket.getLength());
            // 2. 根据请求计算响应
            String response = process(request);
            // 3. 把响应结果写回到客户端
            //    根据 response 字符串，构造一个 DatagramPacket
            //    和请求 packet 不同，此处构造响应的时候，需要指定这个包要发给谁
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
                    // requestPacket 是从客户端这里收来的，getSocketAddress 会得到客户端的 ip 何为端口
                    requestPacket.getSocketAddress());

            socket.send(responsePacket);
            // 方面查看，打印一下日志
            // ip 和 端口号 + 请求内容 + 响应内容
            System.out.printf("[响应IP: %s | 响应端口号: %d] req: %s, resp: %s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);
        }
    }

    // 这个方法是希望王根据请求计算响应。
    // 由于当前写的是一个 回显 客户端服务器，请求是啥，响应就是啥。
    // 如果后续写一个其他的服务器，不再是回显了，而是有其他具体的业务，就可以修改 process 的方法，根据需要来重新构造响应。
    // 之所以将计算响应单独构成一个方法，是为了明确，这是服务器中的一个关键环节！！！
    public String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        UdpEchoSever udpEchoSever = new UdpEchoSever(9090);
        udpEchoSever.start();
    }
}
